Skip to content

Conversation

@hpoussin
Copy link
Contributor

On Windows, imported symbols must be searched with '_imp' prefix.
Support imported global variables and imported functions.

On Windows, imported symbols must be searched with '__imp_' prefix.
Support imported global variables and imported functions.
@llvmbot llvmbot added the llvm:mc Machine (object) code label Dec 22, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 22, 2024

@llvm/pr-subscribers-mc

Author: Hervé Poussineau (hpoussin)

Changes

On Windows, imported symbols must be searched with '_imp' prefix.
Support imported global variables and imported functions.


Full diff: https://github.com/llvm/llvm-project/pull/120912.diff

7 Files Affected:

  • (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h (+6-1)
  • (modified) llvm/lib/Target/Mips/MipsISelLowering.cpp (+16-1)
  • (modified) llvm/lib/Target/Mips/MipsISelLowering.h (+27)
  • (modified) llvm/lib/Target/Mips/MipsMCInstLower.cpp (+12-2)
  • (modified) llvm/lib/Target/Mips/MipsSubtarget.h (+2)
  • (added) llvm/test/CodeGen/Mips/dllimport.ll (+55)
  • (added) llvm/test/MC/Mips/coff-relocs-dllimport.ll (+11)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index aa35e7db6bda444..b9a2af3341236a5 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -92,7 +92,12 @@ namespace MipsII {
     MO_CALL_LO16,
 
     /// Helper operand used to generate R_MIPS_JALR
-    MO_JALR
+    MO_JALR,
+
+    /// MO_DLLIMPORT - On a symbol operand "FOO", this indicates that the
+    /// reference is actually to the "__imp_FOO" symbol.  This is used for
+    /// dllimport linkage on windows.
+    MO_DLLIMPORT = 0x20,
   };
 
   enum {
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index d5f38c414e703d2..469b7a566cea25c 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -2146,6 +2146,14 @@ SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op,
   GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
   const GlobalValue *GV = N->getGlobal();
 
+  if (GV->hasDLLImportStorageClass()) {
+    assert(Subtarget.isTargetWindows() &&
+           "Windows is the only supported COFF target");
+    return getDllimportVariable(
+        N, SDLoc(N), Ty, DAG, DAG.getEntryNode(),
+        MachinePointerInfo::getGOT(DAG.getMachineFunction()));
+  }
+
   if (!isPositionIndependent()) {
     const MipsTargetObjectFile *TLOF =
         static_cast<const MipsTargetObjectFile *>(
@@ -3501,7 +3509,14 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   }
 
   if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
-    if (IsPIC) {
+    if (Subtarget.isTargetCOFF() &&
+        G->getGlobal()->hasDLLImportStorageClass()) {
+      assert(Subtarget.isTargetWindows() &&
+             "Windows is the only supported COFF target");
+      auto PtrInfo = MachinePointerInfo();
+      Callee = DAG.getLoad(Ty, DL, Chain,
+                           getDllimportSymbol(G, SDLoc(G), Ty, DAG), PtrInfo);
+    } else if (IsPIC) {
       const GlobalValue *Val = G->getGlobal();
       InternalLinkage = Val->hasInternalLinkage();
 
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index e245c056de6491e..efd0acef961f616 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -487,6 +487,33 @@ class TargetRegisterClass;
           DAG.getNode(MipsISD::GPRel, DL, DAG.getVTList(Ty), GPRel));
     }
 
+    // This method creates the following nodes, which are necessary for
+    // loading a dllimported symbol:
+    //
+    // (lw (add (shl(%high(sym), 16), %low(sym)))
+    template <class NodeTy>
+    SDValue getDllimportSymbol(NodeTy *N, const SDLoc &DL, EVT Ty,
+                               SelectionDAG &DAG) const {
+      SDValue Hi =
+          getTargetNode(N, Ty, DAG, MipsII::MO_ABS_HI | MipsII::MO_DLLIMPORT);
+      SDValue Lo =
+          getTargetNode(N, Ty, DAG, MipsII::MO_ABS_LO | MipsII::MO_DLLIMPORT);
+      return DAG.getNode(ISD::ADD, DL, Ty, DAG.getNode(MipsISD::Lo, DL, Ty, Lo),
+                         DAG.getNode(MipsISD::Hi, DL, Ty, Hi));
+    }
+
+    // This method creates the following nodes, which are necessary for
+    // loading a dllimported global variable:
+    //
+    // (lw (lw (add (shl(%high(sym), 16), %low(sym))))
+    template <class NodeTy>
+    SDValue getDllimportVariable(NodeTy *N, const SDLoc &DL, EVT Ty,
+                                 SelectionDAG &DAG, SDValue Chain,
+                                 const MachinePointerInfo &PtrInfo) const {
+      return DAG.getLoad(Ty, DL, Chain, getDllimportSymbol(N, DL, Ty, DAG),
+                         PtrInfo);
+    }
+
     /// This function fills Ops, which is the list of operands that will later
     /// be used when a function call node is created. It also generates
     /// copyToReg nodes to set up argument registers.
diff --git a/llvm/lib/Target/Mips/MipsMCInstLower.cpp b/llvm/lib/Target/Mips/MipsMCInstLower.cpp
index b0642f3d1ff283a..e01d0d1e65cf7e9 100644
--- a/llvm/lib/Target/Mips/MipsMCInstLower.cpp
+++ b/llvm/lib/Target/Mips/MipsMCInstLower.cpp
@@ -18,6 +18,7 @@
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -38,8 +39,16 @@ MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
   MipsMCExpr::MipsExprKind TargetKind = MipsMCExpr::MEK_None;
   bool IsGpOff = false;
   const MCSymbol *Symbol;
+  SmallString<128> Name;
+  unsigned TargetFlags = MO.getTargetFlags();
 
-  switch(MO.getTargetFlags()) {
+  if (TargetFlags & MipsII::MO_DLLIMPORT) {
+    // Handle dllimport linkage
+    Name += "__imp_";
+    TargetFlags &= ~MipsII::MO_DLLIMPORT;
+  }
+
+  switch (TargetFlags) {
   default:
     llvm_unreachable("Invalid target flag!");
   case MipsII::MO_NO_FLAG:
@@ -125,7 +134,8 @@ MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
     break;
 
   case MachineOperand::MO_GlobalAddress:
-    Symbol = AsmPrinter.getSymbol(MO.getGlobal());
+    AsmPrinter.getNameWithPrefix(Name, MO.getGlobal());
+    Symbol = Ctx->getOrCreateSymbol(Name);
     Offset += MO.getOffset();
     break;
 
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h b/llvm/lib/Target/Mips/MipsSubtarget.h
index c048ab29d5f9b2e..85cf45d4702ae81 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.h
+++ b/llvm/lib/Target/Mips/MipsSubtarget.h
@@ -301,6 +301,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
     return (HasSym32 && isABI_N64()) || isABI_N32() || isABI_O32();
   }
   bool isSingleFloat() const { return IsSingleFloat; }
+  bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); }
   bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
   bool hasVFPU() const { return HasVFPU; }
   bool inMips16Mode() const { return InMips16Mode; }
@@ -356,6 +357,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
   bool os16() const { return Os16; }
 
   bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); }
+  bool isTargetWindows() const { return TargetTriple.isOSWindows(); }
 
   bool isXRaySupported() const override { return true; }
 
diff --git a/llvm/test/CodeGen/Mips/dllimport.ll b/llvm/test/CodeGen/Mips/dllimport.ll
new file mode 100644
index 000000000000000..385199892821e7d
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/dllimport.ll
@@ -0,0 +1,55 @@
+; RUN: llc -mtriple mipsel-windows < %s | FileCheck %s
+
+@Var1 = external dllimport global i32
+@Var2 = available_externally dllimport unnamed_addr constant i32 1
+
+declare dllimport void @fun()
+
+define available_externally dllimport void @inline1() {
+	ret void
+}
+
+define available_externally dllimport void @inline2() alwaysinline {
+	ret void
+}
+
+declare void @dummy(...)
+
+define void @use() nounwind {
+; CHECK:     lui $1, %hi(__imp_fun)
+; CHECK:     addiu $1, $1, %lo(__imp_fun)
+; CHECK:     lw $25, 0($1)
+; CHECK:     jalr $25
+  call void @fun()
+
+; CHECK:     lui $1, %hi(__imp_inline1)
+; CHECK:     addiu $1, $1, %lo(__imp_inline1)
+; CHECK:     lw $25, 0($1)
+; CHECK:     jalr $25
+  call void @inline1()
+
+; CHECK:     lui $1, %hi(__imp_inline2)
+; CHECK:     addiu $1, $1, %lo(__imp_inline2)
+; CHECK:     lw $25, 0($1)
+; CHECK:     jalr $25
+  call void @inline2()
+
+; CHECK:     lui $1, %hi(__imp_Var2)
+; CHECK:     addiu $1, $1, %lo(__imp_Var2)
+; CHECK:     lw $1, 0($1)
+; CHECK:     lw $5, 0($1)
+; CHECK:     lui $1, %hi(__imp_Var1)
+; CHECK:     addiu $1, $1, %lo(__imp_Var1)
+; CHECK:     lw $1, 0($1)
+; CHECK:     lw $4, 0($1)
+  %1 = load i32, ptr @Var1
+  %2 = load i32, ptr @Var2
+  call void(...) @dummy(i32 %1, i32 %2)
+
+  ret void
+}
+
+; CHECK: fp:
+; CHECK-NEXT: .long fun
+@fp = constant ptr @fun
+
diff --git a/llvm/test/MC/Mips/coff-relocs-dllimport.ll b/llvm/test/MC/Mips/coff-relocs-dllimport.ll
new file mode 100644
index 000000000000000..a4d189faefdbcbb
--- /dev/null
+++ b/llvm/test/MC/Mips/coff-relocs-dllimport.ll
@@ -0,0 +1,11 @@
+; RUN: llc -mtriple mipsel-windows -filetype obj < %s | llvm-objdump --reloc - | FileCheck %s
+
+declare dllimport void @fun()
+
+define void @use() nounwind {
+; CHECK: 00000008 IMAGE_REL_MIPS_REFHI     __imp_fun
+; CHECK: 0000000c IMAGE_REL_MIPS_REFLO     __imp_fun
+  call void() @fun()
+
+  ret void
+}

@hpoussin
Copy link
Contributor Author

This is an extract of PR #107744

@github-actions
Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 0575815b70b486240ace728a33f756cea8fe58fa 3289d9c3b7191456abc642ddc148b643b38c4d02 --extensions h,cpp -- llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h llvm/lib/Target/Mips/MipsISelLowering.cpp llvm/lib/Target/Mips/MipsISelLowering.h llvm/lib/Target/Mips/MipsMCInstLower.cpp llvm/lib/Target/Mips/MipsSubtarget.h
View the diff from clang-format here.
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
index b9a2af3341..11852681be 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h
@@ -27,118 +27,118 @@ namespace llvm {
 ///
 namespace MipsII {
   /// Target Operand Flag enum.
-  enum TOF {
-    //===------------------------------------------------------------------===//
-    // Mips Specific MachineOperand flags.
-
-    MO_NO_FLAG,
-
-    /// MO_GOT - Represents the offset into the global offset table at which
-    /// the address the relocation entry symbol resides during execution.
-    MO_GOT,
-
-    /// MO_GOT_CALL - Represents the offset into the global offset table at
-    /// which the address of a call site relocation entry symbol resides
-    /// during execution. This is different from the above since this flag
-    /// can only be present in call instructions.
-    MO_GOT_CALL,
-
-    /// MO_GPREL - Represents the offset from the current gp value to be used
-    /// for the relocatable object file being produced.
-    MO_GPREL,
-
-    /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
-    /// address.
-    MO_ABS_HI,
-    MO_ABS_LO,
-
-    /// MO_TLSGD - Represents the offset into the global offset table at which
-    // the module ID and TSL block offset reside during execution (General
-    // Dynamic TLS).
-    MO_TLSGD,
-
-    /// MO_TLSLDM - Represents the offset into the global offset table at which
-    // the module ID and TSL block offset reside during execution (Local
-    // Dynamic TLS).
-    MO_TLSLDM,
-    MO_DTPREL_HI,
-    MO_DTPREL_LO,
-
-    /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial
-    // Exec TLS).
-    MO_GOTTPREL,
-
-    /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from
-    // the thread pointer (Local Exec TLS).
-    MO_TPREL_HI,
-    MO_TPREL_LO,
-
-    // N32/64 Flags.
-    MO_GPOFF_HI,
-    MO_GPOFF_LO,
-    MO_GOT_DISP,
-    MO_GOT_PAGE,
-    MO_GOT_OFST,
-
-    /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a
-    /// 64-bit symbol address.
-    MO_HIGHER,
-    MO_HIGHEST,
-
-    /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs.
-    MO_GOT_HI16,
-    MO_GOT_LO16,
-    MO_CALL_HI16,
-    MO_CALL_LO16,
-
-    /// Helper operand used to generate R_MIPS_JALR
-    MO_JALR,
-
-    /// MO_DLLIMPORT - On a symbol operand "FOO", this indicates that the
-    /// reference is actually to the "__imp_FOO" symbol.  This is used for
-    /// dllimport linkage on windows.
-    MO_DLLIMPORT = 0x20,
-  };
-
-  enum {
-    //===------------------------------------------------------------------===//
-    // Instruction encodings.  These are the standard/most common forms for
-    // Mips instructions.
-    //
-
-    // Pseudo - This represents an instruction that is a pseudo instruction
-    // or one that has not been implemented yet.  It is illegal to code generate
-    // it, but tolerated for intermediate implementation stages.
-    Pseudo   = 0,
-
-    /// FrmR - This form is for instructions of the format R.
-    FrmR  = 1,
-    /// FrmI - This form is for instructions of the format I.
-    FrmI  = 2,
-    /// FrmJ - This form is for instructions of the format J.
-    FrmJ  = 3,
-    /// FrmFR - This form is for instructions of the format FR.
-    FrmFR = 4,
-    /// FrmFI - This form is for instructions of the format FI.
-    FrmFI = 5,
-    /// FrmOther - This form is for instructions that have no specific format.
-    FrmOther = 6,
-
-    FormMask = 15,
-    /// IsCTI - Instruction is a Control Transfer Instruction.
-    IsCTI = 1 << 4,
-    /// HasForbiddenSlot - Instruction has a forbidden slot.
-    HasForbiddenSlot = 1 << 5,
-    /// HasFCCRegOperand - Instruction uses an $fcc<x> register.
-    HasFCCRegOperand = 1 << 6
-
-  };
-
-  enum OperandType : unsigned {
-    OPERAND_FIRST_MIPS_MEM_IMM = MCOI::OPERAND_FIRST_TARGET,
-    OPERAND_MEM_SIMM9 = OPERAND_FIRST_MIPS_MEM_IMM,
-    OPERAND_LAST_MIPS_MEM_IMM = OPERAND_MEM_SIMM9
-  };
+enum TOF {
+  //===------------------------------------------------------------------===//
+  // Mips Specific MachineOperand flags.
+
+  MO_NO_FLAG,
+
+  /// MO_GOT - Represents the offset into the global offset table at which
+  /// the address the relocation entry symbol resides during execution.
+  MO_GOT,
+
+  /// MO_GOT_CALL - Represents the offset into the global offset table at
+  /// which the address of a call site relocation entry symbol resides
+  /// during execution. This is different from the above since this flag
+  /// can only be present in call instructions.
+  MO_GOT_CALL,
+
+  /// MO_GPREL - Represents the offset from the current gp value to be used
+  /// for the relocatable object file being produced.
+  MO_GPREL,
+
+  /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
+  /// address.
+  MO_ABS_HI,
+  MO_ABS_LO,
+
+  /// MO_TLSGD - Represents the offset into the global offset table at which
+  // the module ID and TSL block offset reside during execution (General
+  // Dynamic TLS).
+  MO_TLSGD,
+
+  /// MO_TLSLDM - Represents the offset into the global offset table at which
+  // the module ID and TSL block offset reside during execution (Local
+  // Dynamic TLS).
+  MO_TLSLDM,
+  MO_DTPREL_HI,
+  MO_DTPREL_LO,
+
+  /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial
+  // Exec TLS).
+  MO_GOTTPREL,
+
+  /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from
+  // the thread pointer (Local Exec TLS).
+  MO_TPREL_HI,
+  MO_TPREL_LO,
+
+  // N32/64 Flags.
+  MO_GPOFF_HI,
+  MO_GPOFF_LO,
+  MO_GOT_DISP,
+  MO_GOT_PAGE,
+  MO_GOT_OFST,
+
+  /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a
+  /// 64-bit symbol address.
+  MO_HIGHER,
+  MO_HIGHEST,
+
+  /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs.
+  MO_GOT_HI16,
+  MO_GOT_LO16,
+  MO_CALL_HI16,
+  MO_CALL_LO16,
+
+  /// Helper operand used to generate R_MIPS_JALR
+  MO_JALR,
+
+  /// MO_DLLIMPORT - On a symbol operand "FOO", this indicates that the
+  /// reference is actually to the "__imp_FOO" symbol.  This is used for
+  /// dllimport linkage on windows.
+  MO_DLLIMPORT = 0x20,
+};
+
+enum {
+  //===------------------------------------------------------------------===//
+  // Instruction encodings.  These are the standard/most common forms for
+  // Mips instructions.
+  //
+
+  // Pseudo - This represents an instruction that is a pseudo instruction
+  // or one that has not been implemented yet.  It is illegal to code generate
+  // it, but tolerated for intermediate implementation stages.
+  Pseudo = 0,
+
+  /// FrmR - This form is for instructions of the format R.
+  FrmR = 1,
+  /// FrmI - This form is for instructions of the format I.
+  FrmI = 2,
+  /// FrmJ - This form is for instructions of the format J.
+  FrmJ = 3,
+  /// FrmFR - This form is for instructions of the format FR.
+  FrmFR = 4,
+  /// FrmFI - This form is for instructions of the format FI.
+  FrmFI = 5,
+  /// FrmOther - This form is for instructions that have no specific format.
+  FrmOther = 6,
+
+  FormMask = 15,
+  /// IsCTI - Instruction is a Control Transfer Instruction.
+  IsCTI = 1 << 4,
+  /// HasForbiddenSlot - Instruction has a forbidden slot.
+  HasForbiddenSlot = 1 << 5,
+  /// HasFCCRegOperand - Instruction uses an $fcc<x> register.
+  HasFCCRegOperand = 1 << 6
+
+};
+
+enum OperandType : unsigned {
+  OPERAND_FIRST_MIPS_MEM_IMM = MCOI::OPERAND_FIRST_TARGET,
+  OPERAND_MEM_SIMM9 = OPERAND_FIRST_MIPS_MEM_IMM,
+  OPERAND_LAST_MIPS_MEM_IMM = OPERAND_MEM_SIMM9
+};
 }
 
 inline static MCRegister getMSARegFromFReg(MCRegister Reg) {

@hpoussin
Copy link
Contributor Author

hpoussin commented Dec 22, 2024

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️
You can test this locally with the following command:

View the diff from clang-format here.

I didn't follow clang-format, because it seems unnecessary to reindent the whole TOF enum just to add one member.
Also I don't see why I need to reindent the OperandType enum, which I didn't change.
Maybe because they are located in the MipsII namespace ?

However, if it is required, I can do it.

@hpoussin
Copy link
Contributor Author

Ping

1 similar comment
@hpoussin
Copy link
Contributor Author

hpoussin commented Jan 5, 2025

Ping

@mstorsjo mstorsjo requested a review from wzssyqa January 5, 2025 20:56
@hpoussin
Copy link
Contributor Author

Ping

@hpoussin
Copy link
Contributor Author

Ping. Maybe @wzssyqa or @FlyGoat ?
And any comment on the formatting?

@wzssyqa wzssyqa merged commit 26b87aa into llvm:main Jan 21, 2025
9 of 10 checks passed
@hpoussin hpoussin deleted the clang-mips-coff-10 branch January 21, 2025 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:mc Machine (object) code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants